package intelligentcity.model.turns;

import intelligentcity.conf.Conf;
import intelligentcity.model.Move;
import intelligentcity.model.Point;
import intelligentcity.model.Road;
import intelligentcity.model.streets.HorizontalOneWayStreet;
import intelligentcity.model.streets.OneWayStreet;
import intelligentcity.model.streets.VerticalOneWayStreet;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class Turn extends Road {

    private final OneWayStreet longerHorizontal;
    private final OneWayStreet longerVertical;
    private final OneWayStreet shorterHorizontal;
    private final OneWayStreet shorterVertical;

    private final List<Point> pointsOfTurn;
    private final Corner corner;

    public enum Corner {
        NW, NE, SW, SE
    }

    public Turn(Corner corner, int x, int y, int lenghtNS, int lenghtWE) {

        this.pointsOfTurn = new ArrayList<>(4);
        this.corner = corner;
        pointsOfTurn.add(new Point(x, y));

        switch (corner) {
            case NW:
                longerHorizontal = new HorizontalOneWayStreet(x, y, x + lenghtWE, Move.LEFT);
                longerVertical = new VerticalOneWayStreet(x, y, y + lenghtNS, Move.DOWN);
                shorterHorizontal = new HorizontalOneWayStreet(x + Conf.distanceBeetweenStreets, y
                        + Conf.distanceBeetweenStreets, x + lenghtWE, Move.RIGHT);
                shorterVertical = new VerticalOneWayStreet(x + Conf.distanceBeetweenStreets, y
                        + Conf.distanceBeetweenStreets, y + lenghtNS, Move.UP);
                pointsOfTurn.add(new Point(x + Conf.distanceBeetweenStreets, y + Conf.distanceBeetweenStreets));
                break;

            case NE:
                longerHorizontal = new HorizontalOneWayStreet(x - lenghtWE, y, x, Move.LEFT);
                longerVertical = new VerticalOneWayStreet(x, y, y + lenghtNS, Move.UP);
                shorterHorizontal = new HorizontalOneWayStreet(x - lenghtWE, y
                        + Conf.distanceBeetweenStreets, x - Conf.distanceBeetweenStreets, Move.RIGHT);
                shorterVertical = new VerticalOneWayStreet(x - Conf.distanceBeetweenStreets, y
                        + Conf.distanceBeetweenStreets, y + lenghtNS, Move.DOWN);
                pointsOfTurn.add(new Point(x - Conf.distanceBeetweenStreets, y + Conf.distanceBeetweenStreets));
                break;

            case SW:
                longerHorizontal = new HorizontalOneWayStreet(x, y, x + lenghtWE, Move.RIGHT);
                longerVertical = new VerticalOneWayStreet(x, y - lenghtNS, y, Move.DOWN);
                shorterHorizontal = new HorizontalOneWayStreet(x + Conf.distanceBeetweenStreets, y
                        - Conf.distanceBeetweenStreets, x + lenghtWE, Move.LEFT);
                shorterVertical = new VerticalOneWayStreet(x + Conf.distanceBeetweenStreets, y - lenghtNS, y
                        - Conf.distanceBeetweenStreets, Move.UP);
                pointsOfTurn.add(new Point(x + Conf.distanceBeetweenStreets, y - Conf.distanceBeetweenStreets));
                break;

            case SE:
                longerHorizontal = new HorizontalOneWayStreet(x - lenghtWE, y, x, Move.RIGHT);
                longerVertical = new VerticalOneWayStreet(x, y - lenghtNS, y, Move.UP);
                shorterHorizontal = new HorizontalOneWayStreet(x - lenghtWE, y - Conf.distanceBeetweenStreets, x
                        - Conf.distanceBeetweenStreets, Move.LEFT);
                shorterVertical = new VerticalOneWayStreet(x - Conf.distanceBeetweenStreets, y - lenghtNS, y
                        - Conf.distanceBeetweenStreets, Move.DOWN);
                pointsOfTurn.add(new Point(x - Conf.distanceBeetweenStreets, y - Conf.distanceBeetweenStreets));
                break;

            default:
                longerHorizontal = null;
                longerVertical = null;
                shorterHorizontal = null;
                shorterVertical = null;
                pointsOfTurn.add(null);
        }
    }

    @Override
    public List<OneWayStreet> getOneWayStreets() {
        List<OneWayStreet> oneWayStreets = new LinkedList<>();
        oneWayStreets.add(this.longerHorizontal);
        oneWayStreets.add(this.longerVertical);
        oneWayStreets.add(this.shorterHorizontal);
        oneWayStreets.add(this.shorterVertical);
        return oneWayStreets;
    }

    @Override
    public List<Point> getPointsOfTurn() {
        return pointsOfTurn;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Turn other = (Turn) obj;
        if (longerHorizontal == null) {
            if (other.longerHorizontal != null)
                return false;
        } else if (!longerHorizontal.equals(other.longerHorizontal))
            return false;
        if (longerVertical == null) {
            if (other.longerVertical != null)
                return false;
        } else if (!longerVertical.equals(other.longerVertical))
            return false;
        if (shorterHorizontal == null) {
            if (other.shorterHorizontal != null)
                return false;
        } else if (!shorterHorizontal.equals(other.shorterHorizontal))
            return false;
        if (shorterVertical == null) {
            if (other.shorterVertical != null)
                return false;
        } else if (!shorterVertical.equals(other.shorterVertical))
            return false;
        return true;
    }

    public OneWayStreet getLongerHorizontal() {
        return longerHorizontal;
    }

    public OneWayStreet getLongerVertical() {
        return longerVertical;
    }

    public OneWayStreet getShorterHorizontal() {
        return shorterHorizontal;
    }

    public OneWayStreet getShorterVertical() {
        return shorterVertical;
    }

    public Corner getCorner() {
        return corner;
    }

}
